package com.cooge.sharevideo.base;

import java.lang.reflect.Field;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import com.cooge.sharevideo.annotation.Cooge;

public abstract class BaseDao<T> {

	@Autowired
	@Qualifier("sessionFactory")
	private SessionFactory sessionFactory;

	public abstract Class<T> getEntityClass();

	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	public Query createQuery(String queryString, String... params) {
		Query query = this.getSession().createQuery(queryString);
		for (int i = 0; i <= params.length; i++) {
			query.setParameter(i, params[i]);
		}
		return query;
	}

	public T get(Long id) {
		@SuppressWarnings("unchecked")
		T t = (T) this.getSession().get(getEntityClass(), id);
		return t;
	}

	@SuppressWarnings("unchecked")
	public List<T> getlist() {

		return this.getSession().createCriteria(getEntityClass()).list();

	}

	@SuppressWarnings("unchecked")
	public List<T> getList(T t) {
		Criteria cri = this.getSession().createCriteria(this.getEntityClass());
		cri.add(Example.create(t));
		List<T> list = cri.list();
		return list;
	}

	@SuppressWarnings("unchecked")
	public List<T> getList(T t, String... orders) {
		Criteria cri = this.getSession().createCriteria(this.getEntityClass());
		cri.add(Example.create(t));
		for (String order : orders) {
			cri.addOrder(Order.asc(order));
		}
		List<T> list = cri.list();
		return list;
	}

	@SuppressWarnings("unchecked")
	public T save(T t) {
		return (T) this.getSession().get(getEntityClass(),
				this.getSession().save(t));
	}

	@SuppressWarnings("unchecked")
	public List<T> getPageList(T t, int first, int max) throws Exception {
		Criteria cri = this.CriteriaUtil(t);
		cri.add(Example.create(t));
		cri.setFirstResult(first);
		cri.setMaxResults(max);
		List<T> list = cri.list();
		return list;
	}

	@SuppressWarnings("unchecked")
	public List<T> getPageList(T t, int first, int max, String order, String asc)throws Exception{

		Criteria cri = this.CriteriaUtil(t);

		if ((order != null && (!order.trim().equals("")))
				&& (asc != null && (!asc.trim().equals("")))) {

			if (asc.trim().equals("asc")) {
				cri.addOrder(Order.asc(order));
			}
			if (asc.trim().equals("desc")) {
				cri.addOrder(Order.desc(order));
			}
		}
		cri.setFirstResult(first);
		cri.setMaxResults(max);
		List<T> list = cri.list();
		return list;
	}

	@SuppressWarnings("unchecked")
	public List<T> getPageList(int first, int max) {
		List<T> list = this.getSession().createCriteria(getEntityClass())
				.setFirstResult(first).setMaxResults(max).list();
		return list;
	}

	public long getTotalSize(T t) throws Exception {
		Criteria cri = this.CriteriaUtil(t);
		return ((Long) cri.setProjection(Projections.rowCount()).uniqueResult());

	}
	
	public Criteria getCriteria(T t,int first,int max,String order,String asc){
		  
		Criteria cri = this.getSession().createCriteria(this.getEntityClass());
		if ((order != null && (!order.trim().equals("")))
				&& (asc != null && (!asc.trim().equals("")))) {
			if (asc.trim().equals("asc")) {
				cri.addOrder(Order.asc(order));
			}
			if (asc.trim().equals("desc")) {
				cri.addOrder(Order.desc(order));
			}
		}
		cri.setFirstResult(first);
		cri.setMaxResults(max);
		return cri;
		
	}

	private Criteria CriteriaUtil(T t) throws Exception {
		Criteria cri = this.getSession().createCriteria(this.getEntityClass());

		Class<T> cls = this.getEntityClass();
		Field[] fi = cls.getDeclaredFields();
		for (Field f : fi) {

			if (f.getType().getSimpleName().toLowerCase().equals("boolean")) {
				f.setAccessible(true);
				Object o = f.get(t);
				if (o != null && o.toString().equals("false")) {
					cri.add(Restrictions.or(Restrictions.isNull(f.getName()),
							Restrictions.eq(f.getName(), false)));
				}

			}
			if (f.getType().getSimpleName().toLowerCase().equals("string")) {
				f.setAccessible(true);
				Object o = f.get(t);
				if (o != null) {
					cri.add(Property.forName(f.getName()).like("%" + o.toString().trim() + "%"));
				}

			}
		}
		return cri;
	}
}
